﻿/*  Francis Nino Seisei 
 *  ©2012 Francis Antonio Bolaños Arias.
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Seisei.Global;

namespace Seisei.Nino.Reader
{
    public class Database
    {
        public static Table[] DataMatrix;

        public static bool ReadNino(string Code)
        {
            try
            {

                //Quitar '\n', '(' y dividir en líneas
                string[] Lines = Code.Replace("](", "]").Replace("\n", "").Replace("\r", "").Replace("\t", "").Split(';');

                //Obtener número de Tablas
                int t = -1;
                //Obtener número de Filas de Cada Tabla (Numeros separados por coma)
                int cols = 0;
                string f = "";
                //Si esta leyendo campos de una tabla
                bool inTable = false;
                for (int i = 0; i < Lines.Length; i++)
                {
                    if (!Lines[i].Equals(")"))
                    {
                        if (Lines[i].IndexOf("/*") != -1)
                        {
                            try
                            {
                                while (Lines[i].IndexOf("/*") < Lines[i].IndexOf("*/"))
                                {
                                    //Eliminar comentarios y ')'
                                    Lines[i] = Lines[i].Replace(Lines[i].Substring(Lines[i].IndexOf("/*")
                                        , (Lines[i].IndexOf("*/") + 2) - Lines[i].IndexOf("/*")), "").Replace(")T", "T");
                                }
                            }
                            catch (ArgumentOutOfRangeException)
                            {
                                Memory.ERROR = "ERROR 001: Illegal Commentary found around\n\n'" + Lines[i] + "'";
                                return false;
                            }
                        }
                        //¿Es línea de Tabla?
                        if (Lines[i].ToUpper().Contains("TABLE ["))
                        {
                            t++;
                            if (cols != 0)
                            {
                                f += cols + ",";
                                cols = 0;
                            }
                            inTable = true;
                        }
                        if (inTable)
                        {
                            if (!Lines[i].ToUpper().Contains("IDENTITY")
                                && !Lines[i].ToUpper().Contains("FOREIGN")
                                && !Lines[i].ToUpper().Contains("PRIMARY"))
                            {
                                cols++;
                            }
                        }
                    }
                }
                f += cols + ",";

                //Inicializar la tabla
                DataMatrix = new Table[t + 1];
                string[] Fields = f.Split(',');

                for (int i = 0; i < DataMatrix.Length; i++)
                {
                    DataMatrix[i] = new Table(new Column[int.Parse(Fields[i])]);
                }

                //Lectura y carga de datos
                bool LoadingTable = false;
                t = -1;
                cols = 0;
                for (int i = 0; i < Lines.Length; i++)
                {
                    string[] Line = Lines[i].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

                    try
                    {
                        if (!Line[0].Equals(")"))
                        {
                            try
                            {
                                if (Line[0].ToUpper().Equals("TABLE"))
                                {
                                    LoadingTable = false;
                                }
                                //Instrucción SET
                                if (Line[0].ToUpper().Equals("SET"))
                                {
                                    LoadingTable = false;
                                    if (Line[2].ToUpper().Equals("AS"))
                                    {
                                        switch (Line[1])
                                        {
                                            case "OUTPUT_DBMS":
                                                Parameters.OUTPUT_DBMS = Line[3];
                                                break;
                                            case "OUTPUT_PLAT":
                                                Parameters.OUTPUT_PLAT = Line[3];
                                                break;
                                            case "DB_SERVER":
                                                Parameters.DB_SERVER = Line[3];
                                                break;
                                            case "DB_USER":
                                                Parameters.DB_USER = Line[3];
                                                break;
                                            case "DB_USER_PASS":
                                                Parameters.DB_USER_PASS = Line[3];
                                                break;
                                            case "DATABASE":
                                                Parameters.DATABASE = Line[3];
                                                break;
                                            default:
                                                Memory.ERROR = "ERROR 003: SET instruction uses unrecognized parameter.";
                                                return false;
                                        }
                                    }
                                    else
                                    {
                                        Memory.ERROR = "ERROR 004: SET instruction missing 'AS'.";
                                        return false;
                                    }
                                }
                            }
                            catch (IndexOutOfRangeException)
                            {
                                Memory.ERROR = "ERROR 002: No tables found in code";
                                return false;
                            }

                            //Definición de campo, llave primaria, foránea, identity
                            if (LoadingTable)
                            {
                                if (Line[0].ToUpper().Equals("PRIMARY"))
                                {
                                    for (int j = 0; j < DataMatrix[t].Columns.Length - 1; j++)
                                    {
                                        if (DataMatrix[t].Columns[j].Name.Equals(Line[2]))
                                        {
                                            DataMatrix[t].Columns[j].Primary = true;
                                            j = DataMatrix[t].Columns.Length;
                                        }
                                    }
                                }
                                else if (Line[0].ToUpper().Equals("FOREIGN"))
                                {
                                    try
                                    {
                                        if (Line[3].ToUpper().Equals("FROM"))
                                        {
                                            for (int j = 0; j < DataMatrix[t].Columns.Length - 1; j++)
                                            {
                                                if (DataMatrix[t].Columns[j].Name.Equals(Line[2]))
                                                {
                                                    DataMatrix[t].Columns[j].Foreign = true;
                                                    DataMatrix[t].Columns[j].ForeignTable = Line[4];
                                                    j = DataMatrix[t].Columns.Length;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            Memory.ERROR = "ERROR 006: Foreign key definition missing 'FROM':\n\n" + Lines[i];
                                            return false;
                                        }
                                    }
                                    catch (IndexOutOfRangeException)
                                    {
                                        Memory.ERROR = "ERROR 007: Foreign key definition have wrong syntax:\n\n" + Lines[i];
                                        return false;
                                    }
                                }
                                else if (Line[0].ToUpper().Equals("IDENTITY"))
                                {
                                    for (int j = 0; j < DataMatrix[t].Columns.Length - 1; j++)
                                    {
                                        if (DataMatrix[t].Columns[j].Name.Equals(Line[2]))
                                        {
                                            DataMatrix[t].Columns[j].Identity = true;
                                            j = DataMatrix[t].Columns.Length;
                                        }
                                    }
                                }
                                else
                                {
                                    DataMatrix[t].Columns[cols] = new Column();
                                    DataMatrix[t].Columns[cols].Name = Line[0];
                                    DataMatrix[t].Columns[cols].DataType = Line[1];
                                    try
                                    {
                                        if (Line[2].ToUpper().Equals("NULL"))
                                        {
                                            DataMatrix[t].Columns[cols].Nullable = true;
                                        }
                                        else if ((Line[2] + " " + Line[3]).ToUpper().Equals("NOT NULL"))
                                        {
                                            DataMatrix[t].Columns[cols].Nullable = false;
                                        }
                                        else
                                        {
                                            Memory.ERROR = "ERROR 005: Table Field definition have wrong sintax around:\n\n" + Lines[i];
                                            return false;
                                        }
                                    }
                                    catch (IndexOutOfRangeException)
                                    {
                                        Memory.ERROR = "ERROR 005: Table Field definition have wrong sintax around:\n\n" + Lines[i];
                                        return false;
                                    }
                                    cols++;
                                }
                            }

                            //Instrucción Table
                            if (Line[0].ToUpper().Equals("TABLE"))
                            {
                                if (cols != 0)
                                {
                                    cols = 0;
                                }
                                LoadingTable = true;
                                t++;
                                DataMatrix[t].Name = Line[1].Replace("[", "").Replace("]", "");
                                DataMatrix[t].Columns[cols] = new Column();
                                DataMatrix[t].Columns[cols].Name = Line[2];
                                DataMatrix[t].Columns[cols].DataType = Line[3];
                                try
                                {
                                    if (Line[4].ToUpper().Equals("NULL"))
                                    {
                                        DataMatrix[t].Columns[cols].Nullable = true;
                                    }
                                    else if ((Line[4] + " " + Line[5]).ToUpper().Equals("NOT NULL"))
                                    {
                                        DataMatrix[t].Columns[cols].Nullable = false;
                                    }
                                    else
                                    {
                                        Memory.ERROR = "ERROR 005: Table Field definition have wrong sintax around:\n\n" + Lines[i];
                                        return false;
                                    }
                                }
                                catch (IndexOutOfRangeException)
                                {
                                    Memory.ERROR = "ERROR 005: Table Field definition have wrong sintax around:\n\n" + Lines[i];
                                    return false;
                                }
                                cols++;
                            }
                        }
                    }
                    catch (IndexOutOfRangeException)
                    {
                        Memory.ERROR = "ERROR GEN: Francis's Nino Akairo ha fallado al ejecutar este código Nino.\n Puede intente correrlo de tabla en tabla.";
                        return false;
                    }
                }

                return true;

            }
            catch (OverflowException)
            {
                Memory.ERROR = "ERROR 002: No tables found in code";
                return false;
            }
        }
    }
}
